﻿Imports System
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.Drawing
Imports System.Workflow.ComponentModel.Compiler
Imports System.Workflow.ComponentModel.Design

Namespace System.Workflow.ComponentModel
    <AlternateFlowActivity, SRCategory("Standard"), ToolboxItem(False), Designer(GetType(FaultHandlersActivityDesigner), GetType(IDesigner)), ToolboxBitmap(GetType(FaultHandlersActivity), "Resources.Exceptions.png"), ActivityValidator(GetType(FaultHandlersActivityValidator))> _
    Public NotInheritable Class FaultHandlersActivity
        Inherits CompositeActivity
        Implements IActivityEventListener([Of] ActivityExecutionStatusChangedEventArgs)
        ' Methods
        Public Sub New()
        End Sub

        Public Sub New(ByVal name As String)
            MyBase.New(name)
        End Sub

        Protected Friend Overrides Function Cancel(ByVal executionContext As ActivityExecutionContext) As ActivityExecutionStatus
            If (executionContext Is Nothing) Then
                Throw New ArgumentNullException("executionContext")
            End If
            Dim i As Integer
            For i = 0 To MyBase.EnabledActivities.Count - 1
                Dim activity As Activity = MyBase.EnabledActivities.Item(i)
                If (activity.ExecutionStatus = ActivityExecutionStatus.Executing) Then
                    executionContext.CancelActivity(activity)
                End If
                If ((activity.ExecutionStatus = ActivityExecutionStatus.Canceling) OrElse (activity.ExecutionStatus = ActivityExecutionStatus.Faulting)) Then
                    Return MyBase.ExecutionStatus
                End If
            Next i
            Return ActivityExecutionStatus.Closed
        End Function

        Private Function CanHandleException(ByVal exceptionHandler As FaultHandlerActivity, ByVal et As Type) As Boolean
            Dim faultType As Type = exceptionHandler.FaultType
            If (Not et Is faultType) Then
                Return et.IsSubclassOf(faultType)
            End If
            Return True
        End Function

        Protected Friend Overrides Function Execute(ByVal executionContext As ActivityExecutionContext) As ActivityExecutionStatus
            If (executionContext Is Nothing) Then
                Throw New ArgumentNullException("executionContext")
            End If
            Dim e As Exception = [TryCast](MyBase.Parent.GetValue(ActivityExecutionContext.CurrentExceptionProperty),Exception)
            If (Not e Is Nothing) Then
                Dim et As Type = e.GetType
                Dim activity As FaultHandlerActivity
                For Each activity In MyBase.EnabledActivities
                    If Me.CanHandleException(activity, et) Then
                        MyBase.Parent.RemoveProperty(ActivityExecutionContext.CurrentExceptionProperty)
                        activity.SetException(e)
                        activity.RegisterForStatusChange(Activity.ClosedEvent, Me)
                        executionContext.ExecuteActivity(activity)
                        Return ActivityExecutionStatus.Executing
                    End If
                Next
            End If
            Return ActivityExecutionStatus.Closed
        End Function

        Protected Friend Overrides Sub Initialize(ByVal provider As IServiceProvider)
            If (MyBase.Parent Is Nothing) Then
                Throw New InvalidOperationException(SR.GetString("Error_MustHaveParent"))
            End If
            MyBase.Initialize(provider)
        End Sub

        Protected Friend Overrides Sub OnActivityChangeRemove(ByVal executionContext As ActivityExecutionContext, ByVal removedActivity As Activity)
            If (removedActivity Is Nothing) Then
                Throw New ArgumentNullException("removedActivity")
            End If
            If (executionContext Is Nothing) Then
                Throw New ArgumentNullException("executionContext")
            End If
            If ((removedActivity.ExecutionStatus = ActivityExecutionStatus.Closed) AndAlso (MyBase.ExecutionStatus <> ActivityExecutionStatus.Closed)) Then
                Me.activeChildRemoved = True
            End If
            MyBase.OnActivityChangeRemove(executionContext, removedActivity)
        End Sub

        Protected Overrides Sub OnClosed(ByVal provider As IServiceProvider)
        End Sub

        Protected Friend Overrides Sub OnWorkflowChangesCompleted(ByVal executionContext As ActivityExecutionContext)
            If (executionContext Is Nothing) Then
                Throw New ArgumentNullException("executionContext")
            End If
            If Me.activeChildRemoved Then
                executionContext.CloseActivity
                Me.activeChildRemoved = False
            End If
            MyBase.OnWorkflowChangesCompleted(executionContext)
        End Sub

        Private Sub System.Workflow.ComponentModel.IActivityEventListener<System.Workflow.ComponentModel.ActivityExecutionStatusChangedEventArgs>.OnEvent(ByVal sender As Object, ByVal e As ActivityExecutionStatusChangedEventArgs) Implements IActivityEventListener([Of] ActivityExecutionStatusChangedEventArgs).OnEvent
            If (sender Is Nothing) Then
                Throw New ArgumentNullException("sender")
            End If
            If (e Is Nothing) Then
                Throw New ArgumentNullException("e")
            End If
            Dim context As ActivityExecutionContext = [TryCast](sender,ActivityExecutionContext)
            If (context Is Nothing) Then
                Throw New ArgumentException("Error_SenderMustBeActivityExecutionContext", "sender")
            End If
            e.Activity.UnregisterForStatusChange(Activity.ClosedEvent, Me)
            context.CloseActivity
        End Sub


        ' Fields
        <NonSerialized> _
        Private activeChildRemoved As Boolean
    End Class
End Namespace

